using System;
using System.Diagnostics;
using System.Configuration;
using System.IO;

namespace uk.co.tonyditchfield.utility.logging
{
    /// <summary>
    /// Generic Logging class. Must be instantiated from ILog
    /// </summary>
    public class Log : LoggingLevel, ILog
    {
        /// <summary>
        /// Static construct allowing population from config file
        /// </summary>
        static Log()
        {
            if (ApplicationName == null)
            {
                ApplicationName = ConfigurationManager.AppSettings.Get("ApplicationName");
                if (ApplicationName == null)
                    ApplicationName = notUsed;
            }
            SetLoggingLevel(ConfigurationManager.AppSettings.Get("LoggingLevel"));

            if (LogFile == null)
            {
                LogFile = ConfigurationManager.AppSettings.Get("LoggingFile");
                if (LogFile != null) // its been set
                {
                    logToFile = File.AppendText(LogFile);
                }
                else
                {
                    LogFile = notUsed;
                }
            }
            if (!EventLog.SourceExists(ApplicationName, "."))
            {
                EventLog.CreateEventSource(ApplicationName, "Application");
            }
        }

        private static string notUsed = "NotUsed";
        private static EventLog eventLog = new EventLog();
        private static StreamWriter logToFile;

        private static string applicationName = null;
        private static string ApplicationName
        {
            get { return applicationName; }
            set { applicationName = value; }
        }

        private static string logFile = null;
        private static string LogFile
        {
            get { return Log.logFile; }
            set { Log.logFile = value; }
        }

        #region ILog Members

        void ILog.LogError(string error)
        {
            LogEntry(error, EventLogEntryType.Error);
        }

        void ILog.LogError(Exception exception)
        {
            LogEntry(exception, EventLogEntryType.Error);
        }

        void ILog.LogWarning(string error)
        {
            LogEntry(error, EventLogEntryType.Warning);
        }

        void ILog.LogWarning(Exception exception)
        {
            LogEntry(exception, EventLogEntryType.Warning);
        }

        void ILog.LogInfo(string error)
        {
            LogEntry(error, EventLogEntryType.Information);
        }

        void ILog.LogInfo(Exception exception)
        {
            LogEntry(exception, EventLogEntryType.Information);
        }

        #endregion

        private void LogEntry(string message, EventLogEntryType eventType)
        {
            if (LogLevel >= eventType)
            {
                WriteToLog(message, eventType);
                WriteToFile(message, eventType);
            }
        }

        private void LogEntry(Exception exception, EventLogEntryType eventType)
        {
            LogEntry(exception.Message + "\r\n" + exception.StackTrace, eventType);
        }

        private void WriteToLog(string message, EventLogEntryType eventType)
        {
            if (ApplicationName != notUsed)
            {
                eventLog.Source = ApplicationName;
                eventLog.WriteEntry(message, eventType);
            }
        }

        private void WriteToFile(string logMessage, EventLogEntryType eventType)
        {
            if (logToFile != null)
            {
                DateTime now = DateTime.Now;
                logToFile.Write("\r\nLog Entry : " + eventType.ToString() + " : ");
                logToFile.WriteLine("{0} {1}", now.ToLongDateString(),
                    now.ToLongTimeString() + ":" + now.Millisecond);
                logToFile.WriteLine(" :{0}", logMessage);
                logToFile.WriteLine("-------------------------------");
                // Update the underlying file.
                logToFile.Flush();
            }
        }
    }
}
